import pyamf.flex.messaging as messaging
import pyamf.remoting.client as service
import pyamf.remoting as remoting
import pyamf

import Lib.Logger.log4py as logging
import os
import requests
import requests.cookies
import urllib.parse
import pickle
import json
import time

from mj_parser import common_errors

def request_with_relogin(func):

    def func_wrapper(self, *args, **kwargs):
        returned = func(self, *args, **kwargs)
        if returned.status_code in (302, 502) or returned.headers['content-type'].startswith('text/html'):
            self.logger.debug("received status {0} for request".format(str(returned.status_code)))
            self.update_cookies()
            return func(self, *args, **kwargs)
        return returned

    return func_wrapper


def decode_amf(func):

    def func_wrapper(self, *args, **kwargs):
        returned = func(self, *args, **kwargs)
        if not returned:
            self.logger.debug('Possible login error')
            return None

        if returned.status_code < 300 and returned.headers['content-type'].startswith('application/x-amf'):
            envelope = remoting.decode(returned.content, logger=self.logger)
            return envelope
        else:
            self.logger.debug('Possible login error: {0}'.format(returned.content))

        return None

    return func_wrapper


class FordBrand:
    cookie_file = "ford_cookie.txt"
    url_file = "ford_url.txt"
    user_name = "parts@A02160.CAF.SO"
    password = "000000"
    company_id = '53f62452e4b009ed8037682a'
    subscription_id = 'DYN0000000001A83DD'
    dsid = 'CE99517D-F11A-13A0-7F48-E3C369BB1ECB'
    message_id = '31EE06F8-0ACF-3813-2BA7-086FC45DFAFF'
    url = ''


class FordWebSource:
    LOGIN = 'https://login.superservice.com/landingpage/services/authentication/loginandgoto.json'
    USER = 'https://login.superservice.com/landingpage/services/user/current.json'
    DISCOVERY = 'https://login.superservice.com/landingpage/services/application' + \
                '/info.json?preferredCompanyId={0}&rand=1487419496639'

    def __init__(self, root_path='.', profile=FordBrand):
        self.logger = logging.get_logger("crawler", "FordWebSource." + profile.__class__.__name__)

        self.profile = profile

        self.root_path = root_path
        self.cookie_path = os.path.join(root_path, 'conf')
        self.cookie_file = os.path.join(root_path, 'conf', profile.cookie_file)
        self.cookie_str = None

        self.url_file = os.path.join(root_path, 'conf', profile.url_file)
        self.data_path = os.path.join(root_path, "data")

        self.timestamp = str(int(time.time() * 1000))
        self.update_cookies()

    def get_data(self, str_vin, brand, group):
        envelope = self.query_vin(str_vin)
        if envelope is None:
            return common_errors.ERR_TCP_ERROR, None

        content = envelope.bodies[0][1]
        payload = content.body.body
        catalog = payload.get('catalog', None)

        if catalog is None:
            return common_errors.ERR_NO_VIN, None

        catalog_json = json.dumps(catalog, ensure_ascii=False)
        print(catalog_json)


        vin_file = os.path.join(self.data_path, '{0}.json'.format(str_vin))
        with open(vin_file, 'w', encoding='utf-8') as fo:
            fo.write(catalog_json)

        return common_errors.ERR_SUCCESS, vin_file

    def query_vin(self, vin):
        message = {
            'body': ['0', vin, '', 100, False, False, True, False],
            'destination': 'catalog',
            'operation': 'searchCatalogWithSections',
            'messageId': self.profile.message_id,
            'headers': {
                'X-IFM-SID': self.profile.subscription_id,
                'DSId': self.profile.dsid,
                'MARKET': 'CN',
                'X-IFM-SESSIONID': None,
                'DSEndPoint': None
            }
        }
        return self.query(message)

    @decode_amf
    @request_with_relogin
    def query(self, message_kwargs):
        client = service.RemotingService(self.profile.url, amf_version=pyamf.AMF3, logger=self.logger)
        message = (messaging.RemotingMessage(**message_kwargs),)
        request_wrapper = client.addRequest('null', *message)
        req_content = remoting.encode(client.getAMFRequest([request_wrapper])).getvalue()

        header = {
            'Content-Type': remoting.CONTENT_TYPE,
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36',
            'Referer': ''
        }

        return requests.post(self.profile.url, data=req_content, headers=header, cookies=self.cookie_str,
                             allow_redirects=False, verify=False)

    def save_url(self):
        if not os.path.exists(self.cookie_path):
            os.makedirs(self.cookie_path)
        with open(self.url_file, 'w') as fo:
            fo.write(self.profile.url)

    def load_url(self):
        with open(self.url_file, 'r') as fi:
            url = fi.read()
            if url:
                self.profile.url = url

    def save_cookies(self):
        if not os.path.exists(self.cookie_path):
            os.makedirs(self.cookie_path)
        with open(self.cookie_file, 'wb') as fo:
            pickle.dump(self.cookie_str, fo)

    def update_cookies(self):
        login_data = {
            "errorgoto": "https://login.superservice.com/login/index.html?errorCode=1",
            "goto": "https://login.superservice.com/landingpage/en-au/",
            "username": self.profile.user_name,
            "password": self.profile.password
        }
        headers = {
            'referer': self.profile.url
        }
        returned = requests.post(FordWebSource.LOGIN, data=login_data, allow_redirects=False, headers=headers, verify=False)
        if returned.status_code == 303:
            cookie_obj = returned.json()
            self.cookie_str = requests.cookies.RequestsCookieJar()
            self.cookie_str.set('Authorization', cookie_obj['accessToken'], domain='login.superservice.com',
                                path='/')

            returned = requests.get(self.USER, headers=headers, cookies=self.cookie_str, verify=False)
            if returned.status_code == 200:
                self.profile.company_id = returned.json()['primaryAccountId']
                self.timestamp = str(int(time.time() * 1000))

            discovery_url = self.DISCOVERY.format(self.profile.company_id)
            returned = requests.get(discovery_url, headers=headers, cookies=self.cookie_str, verify=False)
            if returned.status_code == 200:
                obj = returned.json()
                self.profile.url = obj['applicationInfo'][0]['url'] + '/epc/amfbroker/amf'
                self.profile.subscription_id = obj['applicationInfo'][0]['reference']['subscriptionAssignmentId']
                self.save_url()

            parsed = urllib.parse.urlparse(self.profile.url, scheme='https')
            self.cookie_str.set('Authorization', cookie_obj['accessToken'], domain=parsed.hostname,
                                path='/')
            self.save_cookies()

    def load_cookie(self):
        self.cookie_str = None
        if not os.path.exists(self.cookie_file):
            return
        with open(self.cookie_file, 'rb') as fi:
            self.cookie_str = pickle.load(fi)


if __name__ == '__main__':
    crawler = FordWebSource()
    code, vin_file = crawler.get_data('LVSHJCAC7HE234695', 'ford', '')
    print(code)
    print(vin_file)
